/*
 * @version: 1.0
 * @Author: zhl
 * @Date: 2021-08-20 11:20:27
 * @LastEditors: zhl
 * @LastEditTime: 2021-09-30 17:04:35
 * @Description: file content
 */
/*
 *                        _oo0oo_
 *                       o8888888o
 *                       88" . "88
 *                       (| -_- |)
 *                       0\  =  /0
 *                     ___/`---'\___
 *                   .' \\|     |// '.
 *                  / \\|||  :  |||// \
 *                 / _||||| -:- |||||- \
 *                |   | \\\  - /// |   |
 *                | \_|  ''\---/''  |_/ |
 *                \  .-\__  '-'  ___/-. /
 *              ___'. .'  /--.--\  `. .'___
 *           ."" '<  `.___\_<|>_/___.' >' "".
 *          | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 *          \  \ `_.   \_ __\ /__ _/   .-` /  /
 *      =====`-.____`.___ \_____/___.-`___.-'=====
 *                        `=---='
 * 
 * 
 *      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * 
 *            佛祖保佑       永不宕机     永无BUG
 * 
 *        佛曰:  
 *                写字楼里写字间，写字间里程序员；  
 *                程序人员写程序，又拿程序换酒钱。  
 *                酒醒只在网上坐，酒醉还来网下眠；  
 *                酒醉酒醒日复日，网上网下年复年。  
 *                但愿老死电脑间，不愿鞠躬老板前；  
 *                奔驰宝马贵者趣，公交自行程序员。  
 *                别人笑我忒疯癫，我笑自己命太贱；  
 *                不见满街漂亮妹，哪个归得程序员？
 * 
 */

#include "dbif.h"
#include "CPEMD.h"
#include "CConfigManager.h"
#include "CLogger.h"
#include "CModuleManager.h"
#include "CMosquittoManager.h"
#include "CReportManager.h"
#include "IModule.h"
#include "common.h"
#include "TaskManager.h"
#include "app.h"
#include "SerialProxy.h"
#include "CloudEdgeManager.h"
#include "JsonManager.h"
#include "json.hpp"
#include "Settings.h"
#include "SysinfoManager.h"
#include "global_data_struct.h"
#include "DCData.h"
#include "version.h"
#include "NetManager.h"
#include "../../datacenter/include/DataCenterManager.h"
#include "../../datacenter/include/MappingRelationManager.h"
#include "../../iec104/include/Iec104CommHandler.h"
#include "CLocalMqttManager.h"
#include "LicenseManager.h"

#include <unordered_map>
#include <typeinfo>
#include <iostream>
#include <unistd.h>
#include <cstddef>
#include <sys/timeb.h>
#include <regex>

using namespace std;
using json = nlohmann::json;


#define UART_CHANGE_MODE_TOPIC(PORT) "uartManager/Broadcast/JSON/report/notification/"+PORT+"/modeChange"
#define UART_SET_MODE_TOPIC(APPNAME, PORT)   APPNAME "/uartManager/JSON/set/request/"+PORT+"/workMode"

#define SET_CONFIG_TOPIC(sn)   "c2d/"+sn+"/command/default/v1"
#define RULE_COMMAND_TOPIC(sn) "c2d/"+sn+"/command/default/v1"
#define RAW_COMMAND_TOPIC(sn)  "c2d/"+sn+"/command/default/v1"
#define LINKAGE_TOPIC      "pemd/rule/linkage/pemd/v1/default"
#define CMD_SET_REQUEST    "+/pemd/JSON/set/request"
#define CMD_SET_RESPONSE(APPNAME)   "pemd/"+APPNAME+"/JSON/set/response"
#define ROOT_DIR               "/data/app/pemd"

#define TASK_PARAMS_INIT(DEV_ID,TASK_ID,REQ_ID,PRIORITY,DEV,TOPIC,TYPE,CMD_SRC,ITEMS) TASK_PARAMS param;\
        {                                       \
            param.dev_id    = DEV_ID;           \
            param.task_id   = TASK_ID;          \
            param.req_id    = REQ_ID;           \
            param.type      = TYPE;             \
            param.dev       = DEV;              \
            param.priority  = PRIORITY;         \
            param.topic     = TOPIC;            \
            param.cmd_source= CMD_SRC;          \
            param.items.swap(ITEMS);            \
        }                                       


char     mosquitto_addr[64] = "172.17.0.1";
uint16_t mosquitto_port = 1883;
char     cloud_mosquitto_addr[64] = "47.92.198.35";
uint16_t cloud_mosquitto_port = 1883;
char     cloud_username[32] = "admin";
char     cloud_password[32] = "8048";
char     upload_log_url[128] = "http://47.92.198.35:8092/edgeLog/upload";


int      log_level = SPDLOG_LEVEL_INFO;
int      log_size  = 16*1024*1024;
char     log_filename[256] = ROOT_DIR"/log/logger.log";
char     module_dir[256] = "../module";
char     settings_filename[256] = ROOT_DIR"/conf/settings.conf";
char     **g_argv;
char     g_sn[64] = "0000000000000000";
//
bool     g_is_set_uart_mode_by_myself = false;
//
//未收到104主站的数据，时间间隔(秒)
int      g_no_recvdata_time = 600;

bool     g_is_always_link_cloud = false;
//是否配置104北向
bool     g_104north_enable = false;

std::shared_ptr<CMosquittoManager> g_mosquitto_manager = std::make_shared<CMosquittoManager>();
//任务管理
std::shared_ptr<TaskManager> g_tm = std::make_shared<TaskManager>();
//配置管理
std::shared_ptr<CConfigManager> g_cm = std::make_shared<CConfigManager>();
//云边通信管理
std::shared_ptr<CloudEdgeManager> g_crm = nullptr;
//数据中心通信管理
std::shared_ptr<DataCenterManager> g_dcm = nullptr;
//iec104模块
std::shared_ptr<CIec104CommHandler> g_iec104comm = nullptr;
typedef void (*TFUNCTION_INIT)(std::shared_ptr<CConfigManager> , char *, uint16_t);


std::string get_version(){
	return PROJECT_VER;
}
std::string get_code(){
	return PTOJECT_VER_CODE;
}
//处理串口模式，可优化
void handle_uart_mode(std::string port){
    if(port.empty() || (nullptr == g_cm)){
        return ;
    }
    //获取串口信息
    std::string addr = "";
    for(auto if_addr = g_cm->get_interfaces()->begin(); if_addr != g_cm->get_interfaces()->end(); if_addr++){
        if(0 == if_addr->second.compare(port)){
            addr = if_addr->first;
            break;
        }
    }
    if(addr.empty()){
        return ;
    }
    auto serial_info = g_cm->get_serial_info(addr);
    if(nullptr == serial_info){
        return ;
    }
    //串口模式参数
    g_is_set_uart_mode_by_myself = true;
    std::string msg = JsonManager::getInstance().get_serial_info_json_str(serial_info);
    std::string tmp_topic = "";
    tmp_topic = UART_SET_MODE_TOPIC("pemd", port);
    g_mosquitto_manager->publish(tmp_topic.c_str(), msg.length(), msg.c_str());
    //暂时无用
    g_tm->change_uart_mode();
}
//
int subscribe_topics(){
    int ret =  g_mosquitto_manager->subscribe(LINKAGE_TOPIC);
    if(MOSQ_ERR_SUCCESS != ret){
        return MOSQ_ERR_NOT_SUPPORTED;
    }
    ret =  g_mosquitto_manager->subscribe(CMD_SET_REQUEST);
    if(MOSQ_ERR_SUCCESS != ret){
        return MOSQ_ERR_NOT_SUPPORTED;
    }
    std::string topic = SET_CONFIG_TOPIC(std::string(g_sn));
    ret =  g_mosquitto_manager->subscribe(topic.c_str());
    if(MOSQ_ERR_SUCCESS != ret){
        return MOSQ_ERR_NOT_SUPPORTED;
    }

    return MOSQ_ERR_SUCCESS;
}
int get_cmd_protocol_type(int dev_id){
    auto  term_dev = g_cm->get_terminal_device(dev_id);
    if (nullptr == term_dev) {
        CLogger::getInstance()->log_i("不存在该设备:%lld", dev_id);
        return -1;
    }
    auto proto = g_cm->get_protocol_rule(term_dev->protocol_id);
    if(nullptr == proto){
        CLogger::getInstance()->log_i("不存在该协议:%lld", term_dev->protocol_id);
        return -1;
    }
    return proto->protocol_type;
}
int get_cmd_id(int proto_type, std::string name){
    int cmd_id = -1;
    if((0 > proto_type) || name.empty()){
        return cmd_id;
    }
    
    switch(proto_type){
        case 1:
        {
            auto modbus_cmd = CMappingRelationManager::getInstance()->modbus_get_cmd_info(name);
            if(nullptr != modbus_cmd){
                cmd_id = modbus_cmd->id;
            }
        }
        break;
        case 2:
        {
            auto dlt645_cmd = CMappingRelationManager::getInstance()->dlt645_get_cmd_info(name);
            if(nullptr != dlt645_cmd){
                cmd_id = dlt645_cmd->id;
            }
        }
        break;
        default:
        break;
    }
    return cmd_id;
}
int exec_set_cmd(CMD_REQUEST &cmds, std::string appName){
    if(1 > cmds.params.size()){
        CLogger::getInstance()->log_i("无相关设置命令");
        return -1;
    }
    
    auto dev_info = DataCenterManager::getInstance()->get_devguid_withdev(cmds.dev);

    int protocol_type = get_cmd_protocol_type(dev_info->id);
    if(0 > protocol_type){
        CLogger::getInstance()->log_i("不存在该协议");
        return -1;
    }

    std::list<ITEM_PARAMS> items;
    for(auto cmd = cmds.params.begin(); cmd != cmds.params.end(); cmd++){
        ITEM_PARAMS  item;
        item.value = cmd->value;
        item.item_id = get_cmd_id(protocol_type, cmd->name);
        if(0 > item.item_id){
            continue;
        }
        item.order   = cmd->order;
        item.type    = cmd->data_type;
        item.value   = cmd->value;
        items.push_back(item);
    }

    if(0 < items.size()){
        items.sort([] (ITEM_PARAMS a, ITEM_PARAMS b) -> bool {return a.order < b.order;});
        TASK_PARAMS_INIT(dev_info->id,-1,cmds.token,1,cmds.dev,CMD_SET_RESPONSE(appName), TASK_TYPE_SET_CMD_RULE, CMD_FROM_LOCAL, items);
        g_tm->run_cmd(g_cm, g_mosquitto_manager, param);
    }else{
        CLogger::getInstance()->log_i("没有待执行设置指令");
        return -1;
    }

    return 0;    
}
int exec_get_cmd(CMD_REQUEST &cmds, std::string appName){
    if(1 > cmds.params.size()){
        CLogger::getInstance()->log_i("无相关读取命令");
        return -1;
    }

    auto dev_info = DataCenterManager::getInstance()->get_devguid_withdev(cmds.dev);

    int protocol_type = get_cmd_protocol_type(dev_info->id);
    if(0 > protocol_type){
        return -1;
    }

    std::list<ITEM_PARAMS> items;
    for(auto cmd = cmds.params.begin(); cmd != cmds.params.end(); cmd++){
        ITEM_PARAMS  item;
        item.item_id = get_cmd_id(protocol_type, cmd->name);
        if(0 > item.item_id){
            continue;
        }
        item.order   = cmd->order;
        item.type    = cmd->data_type;
        items.push_back(item);
    }

    if(0 < items.size()){
        items.sort([] (ITEM_PARAMS a, ITEM_PARAMS b) -> bool {return a.order < b.order;});
        TASK_PARAMS_INIT(dev_info->id,-1,cmds.token,1,cmds.dev,CMD_SET_RESPONSE(appName), TASK_TYPE_GET_CMD_RULE, CMD_FROM_LOCAL, items);
        g_tm->run_cmd(g_cm, g_mosquitto_manager, param);
    }else{
        CLogger::getInstance()->log_i("没有待执行读取命令");
        return -1;
    }

    return 0;    
}
//MQTT回调函数
int callback(CALLBACK_TYPE cb_type, void *data, int data_len, int result, void *arg){
    CLogger::getInstance()->log_d("主程序本地回调方法(%d)", cb_type);
    try{
        if(cb_type == CALLBACK_TYPE_CONNECTED){
            subscribe_topics();
        } else if(cb_type == CALLBACK_TYPE_MESSAGE){
            struct mosquitto_message *msg = (struct mosquitto_message *)data;
            std::string payload = (char *)msg->payload;
            auto j = json::parse(payload);
            if(0 == strcmp(msg->topic, LINKAGE_TOPIC)){ //联动规则
                //此处需要处理联动规则
                int64_t dev_id = j["dev_id"].get<int64_t>();
                int64_t cmd_id = j["cmd_id"].get<int64_t>();
                std::string value = j["value"].get<std::string>();
                ITEM_PARAMS  item;
                item.value = value;
                item.item_id = cmd_id;
                std::list<ITEM_PARAMS> items;
                items.push_back(item);
                TASK_PARAMS_INIT(dev_id,-1,-1,2,"",LINKAGE_TOPIC,TASK_TYPE_LINKAGE,CMD_FROM_UNKNOWN,items);
                g_tm->run_cmd(g_cm, g_mosquitto_manager, param);
            } else if(true == std::regex_match(msg->topic, std::regex("(\\w+)/pemd/JSON/set/request"))){
                std::string topic = msg->topic;
                std::string appname = topic.substr(0, topic.find_first_of("/"));
                CMD_REQUEST cmds = JsonManager::getInstance().get_cmd_info((char *)msg->payload);
                result = exec_set_cmd(cmds, appname);
            } else if(true == std::regex_match(msg->topic, std::regex("(\\w+)/pemd/JSON/get/request"))){
                std::string topic = msg->topic;
                std::string appname = topic.substr(0, topic.find_first_of("/"));
                CMD_REQUEST cmds = JsonManager::getInstance().get_cmd_info((char *)msg->payload);
                result = exec_get_cmd(cmds, appname);
            } else if(true == std::regex_match(msg->topic, std::regex(SET_CONFIG_TOPIC(std::string(g_sn))))){
                if(0 == strcmp(JsonManager::getInstance().get_command_name(payload).c_str(), "CMD_SET_COMMAND_RULE")){
                    static int req_id = 0;
                    JsonManager::getInstance().run_cmd(g_cm, g_tm, g_mosquitto_manager, TASK_TYPE_SET_CMD_RULE, req_id++, payload);
                }
            } else {
                std::string recv_topic = msg->topic;
                if(recv_topic.find("uartManager/Broadcast/JSON/report/notification/") != std::string::npos){ //串口模式修改
                    std::string v_port = j["port"].get<std::string>();
                    std::string v_mode = j["mode"];
                    std::string tmp_topic = "";
                    tmp_topic = tmp_topic+UART_CHANGE_MODE_TOPIC(v_port);
                    if(!v_mode.compare("master")){
                        handle_uart_mode(v_port);
                    }
                }
                
            }
        }
    } catch(...){
        result = -1;
    }

    CLogger::getInstance()->log_d("%s{%d}", (char *)data, result);
    return result;
}
//
void redirect_modulepath()
{
    char path[256] = {0};
    if(NULL == getcwd(path, sizeof(path))){
        snprintf(path, sizeof(path), "/usr/local/pemd/bin");
    }
    snprintf(module_dir, sizeof(module_dir),"%s/../module",path);

    printf("work dir:%s\nmodule dir:%s\nsettings dir:%s\nlog dir:%s\n", path, module_dir, settings_filename, log_filename);
}
//
void usage(){
    printf("============================================\n");
    printf("-a    set mqtt broker ip address.\n");
    printf("-p    set mqtt broker port.\n");
    printf("-d    set mqtt broker cloud ip address.\n");
    printf("-q    set mqtt broker cloud port.\n");
    printf("-u    set mqtt broker user name.\n");
    printf("-s    set mqtt broker password.\n");
    printf("-l    set log level.\n");
    printf("-n    set log size.\n");
    printf("-c    set config file path.\n");
    //printf("-f    set log file path.\n");
    //printf("-m    set module file path.\n");
    printf("-v    display pemd version.\n");
    printf("-h    help.\n");
    printf("============================================\n");
}
//配置可改成配置文件的形式而非命令行处理
//命令行解析
int parse_cmd(int argc, char* argv[]){
    int ch   = -1;
    while(-1 != (ch = getopt(argc, argv, "a:p:l:vc:r:d:m:n:q:u:s:?h"))){
        switch(ch){
            case 'a': //mosquitto ip addr
                bzero(mosquitto_addr, sizeof(mosquitto_addr));
                strncpy(mosquitto_addr, optarg, sizeof(mosquitto_addr)-1);
            break;
            case 'p':
                mosquitto_port = atoi(optarg);
            break;
            case 'l':
                log_level = atoi(optarg);
                if((6 < log_level) || (0 > log_level)){
                    log_level = SPDLOG_LEVEL_INFO;
                }
            break;
            case 'n':
                log_size = atoi(optarg);
                if(0 > log_size){
                    log_size = 16*1024*1024;
                }
            break;
            case 'm': //module  dir
                bzero(module_dir, sizeof(module_dir));
                strncpy(module_dir, optarg, sizeof(module_dir) - 1);                
            break;
            case 'f': //log file path
                bzero(log_filename, sizeof(log_filename));
                strncpy(log_filename, optarg, sizeof(log_filename)-1);
            break;
            case 'd': //cloud ip addr
                bzero(cloud_mosquitto_addr, sizeof(cloud_mosquitto_addr));
                strncpy(cloud_mosquitto_addr, optarg, sizeof(cloud_mosquitto_addr)-1);
            break;
            case 'q':
                cloud_mosquitto_port = atoi(optarg);
            break;
            case 'u':
                bzero(cloud_username, sizeof(cloud_username));
                strncpy(cloud_username, optarg, sizeof(cloud_username)-1);
            break;
            case 's':
                bzero(cloud_password, sizeof(cloud_password));
                strncpy(cloud_password, optarg, sizeof(cloud_password)-1);
            break;
            case 'c':
                bzero(settings_filename, sizeof(settings_filename));
                strncpy(settings_filename, optarg, sizeof(settings_filename)-1);
            break;
            case 'v':
                printf("pemd version %s(%s),build time:%s,%s\n", get_version().c_str(), get_code().c_str(), __DATE__,__TIME__);
                return -1;
            case 'r':
                g_is_always_link_cloud = atoi(optarg);
            break;
            case '?': //
            case 'h': //help
            default:
                usage();
                return -1;
            break;
        }
    }
    return 0;
}
/**
 * @brief set uart mode
 * 
 */
void init_uart_mode(){
    for(auto ifs = g_cm->get_interfaces()->begin(); ifs != g_cm->get_interfaces()->end(); ifs++){
        handle_uart_mode(ifs->second);
    }
}
//
void init_mosquitto(){
    if(MOSQ_ERR_SUCCESS == g_mosquitto_manager->init(NULL, callback)){
        int ret = g_mosquitto_manager->connect(mosquitto_addr, mosquitto_port, NULL, NULL, 10);
        if(MOSQ_ERR_SUCCESS == ret){
            //配置主题需要沟通后修改
            g_mosquitto_manager->start();
        }else{
            g_mosquitto_manager->stop();
            sleep(2);
            init_mosquitto();
        }
    }
}
//
void subscribe_serial_topic(std::shared_ptr<std::unordered_map<std::string, std::string>> interfaces){
    if(nullptr == interfaces){
        return ;
    }
    //
    for(auto if_it = interfaces->begin(); if_it != interfaces->end(); if_it++){
        std::string topic = UART_CHANGE_MODE_TOPIC(if_it->second);
        g_mosquitto_manager->subscribe(topic.c_str());
    }
}
//
void handle_history_data(uint64_t ts){    
    CDBManager::getInstance()->del_history_data(ts);
}
void handle_alert_data(uint64_t ts){
    CDBManager::getInstance()->del_alert_data(ts);
}
void handle_log_data(uint64_t ts){
    auto terminal_devs = g_cm->get_terminal_devices();
    if(nullptr != terminal_devs){
        for(auto tdev = terminal_devs->begin(); tdev != terminal_devs->end(); tdev++){
            CDBManager::getInstance()->del_log(tdev->first, ts);
        }
    }
}
//
void handle_storage_info(){
    auto edge_dev = g_cm->get_edge_device();
    if(nullptr == edge_dev){
        return ;
    }
    uint64_t before_time = (today_timestamp()-(86400* edge_dev->data_depth))*1000;
    handle_history_data(before_time);
    handle_alert_data(before_time);
    handle_log_data(before_time);
}
//
void init_cloud_edge_communication(){

    g_crm = std::make_shared<CloudEdgeManager>(g_cm, g_tm, g_mosquitto_manager,g_dcm);
    if (g_is_always_link_cloud){
        g_crm->connectBroker(cloud_mosquitto_addr, cloud_mosquitto_port, cloud_username, cloud_password, 10);
    }
}

std::string get_sn(){
    if(1 > get_dev_sn(g_sn, sizeof(g_sn))){
        return "T11111111111111111111111";
    }
    return g_sn;
}

std::string get_register_addr(uint64_t parent_id){
    if((nullptr == g_cm) || (nullptr == g_dcm)){
        return "";
    }
    if(0 < parent_id){
        auto pdev = g_cm->get_terminal_device(parent_id);
        if(nullptr != pdev){
            return pdev->slave_addr;
        }
    }
    return "";
}
//为漏保调控指令
typedef union _PTLK{
    uint8_t value;      //控制命令
    struct{
        uint8_t enable:2;  //0-启动漏电保护，1/2-启动漏电告警   默认为0
        uint8_t time:2;    //额定极限不驱动时间        默认为0
        uint8_t level:4;   //漏电流动作值档位为1-8.    默认为0
    }v;
}PTLK;
std::unordered_map<int64_t, PTLK> g_ptlk_map;

std::string get_ptlk_value(int64_t dev_id, std::string value, std::string cmdName){
    if(cmdName.empty() || value.empty() || (1 > dev_id)){
        return "";
    }
    #if 0
    if(g_ptlk_map.find(dev_id) != g_ptlk_map.end()){
        if(0 == strcmp(cmdName.c_str(), "PTLK_Enable")){
            if(1 == atoi(value.c_str())){
                g_ptlk_map[dev_id].v.enable = 0;
            } else {
                g_ptlk_map[dev_id].v.enable = 1;
            }
        } else if((0 == strcmp(cmdName.c_str(), "PTLK_Alm_Enable")) || (0 == strcmp(cmdName.c_str(), "PTLK_Alm_En"))){
            g_ptlk_map[dev_id].v.enable = atoi(value.c_str());
        } else if((0 == strcmp(cmdName.c_str(), "PTResA_level")) || (0 == strcmp(cmdName.c_str(), "PTResA_strVal"))){
            g_ptlk_map[dev_id].v.level = atoi(value.c_str());
        }
    }
    #endif

    if(0 == strcmp(cmdName.c_str(), "PTLK_Enable")){
            if(1 == atoi(value.c_str())){
                g_ptlk_map[dev_id].v.enable = 0;
            } else {
                g_ptlk_map[dev_id].v.enable = 1;
            }
        } else if((0 == strcmp(cmdName.c_str(), "PTLK_Alm_Enable")) || (0 == strcmp(cmdName.c_str(), "PTLK_Alm_En"))){
            g_ptlk_map[dev_id].v.enable = atoi(value.c_str());
        } else if((0 == strcmp(cmdName.c_str(), "PTResA_level")) || (0 == strcmp(cmdName.c_str(), "PTResA_strVal"))){
            g_ptlk_map[dev_id].v.level = atoi(value.c_str());
        }
    return std::to_string(g_ptlk_map[dev_id].value);
}

int handle_set_value(QUERY_SET_VALUE_DATAS& datas){
    
    if((nullptr == g_cm) || (nullptr == g_dcm)){
        return -1;
    }
    for(auto d = datas.body.begin(); d != datas.body.end(); d++){  //遍历定值列表
        //数据中心查找设备信息
        auto devinfo = g_dcm->get_devguid_withdev(d->dev); 
        if(nullptr == devinfo){
            continue;
        }
        //遍历终端设备列表
        for(auto dev = g_cm->get_terminal_devices()->begin(); dev != g_cm->get_terminal_devices()->end(); dev++){
            //查找地址相同的设备，默认微断地址不同
            std::string parent_addr = get_register_addr(dev->second.parent_id);
            std::string tmp_addr = dev->second.slave_addr;
            if(!parent_addr.empty()){
                tmp_addr = parent_addr + "_" + dev->second.slave_addr;
            }
            if((0 == tmp_addr.compare(devinfo->addr)) && (dev->second.id == devinfo->id)){
                //遍历定值里面待设置的项
                for(auto cmd_name = d->body.begin(); cmd_name != d->body.end(); cmd_name++){
                    //只针对有序充电，遍历645指令列表
                     auto proto = g_cm->get_protocol_rule(dev->second.protocol_id);
                     if(nullptr == proto){
                         continue;
                     }
                    if(proto->protocol_type == 1){//modbus
                         for(auto cmd = g_cm->get_modbus_commands()->begin(); cmd != g_cm->get_modbus_commands()->end(); cmd++){
                            //查找名称相同的指令，获取指令id
                            if(0 == cmd->second.name.compare(cmd_name->name)){
                                //联动设置指令                           
                                CMD_SET_CONST_VALUE data;
                                data.command = "CMD_SET_COMMAND_RULE";
                                data.commandId = 0;
                                data.commandType = "REQ";
                                data.devId = dev->second.id;
                                data.timestamp = get_timestamp();
                                data.params.cmdId = cmd->second.id;
                                data.params.value = cmd_name->val;
                                std::string sendMsg = JsonManager::getInstance().get_set_const_value_msg(data);
                                CLogger::getInstance()->log_i("执行定值设置命令(modbus)：%s", sendMsg.c_str());
                                std::string topic = RULE_COMMAND_TOPIC(std::string(g_sn));
                                g_mosquitto_manager->publish(topic.c_str(), sendMsg.length(), sendMsg.c_str());
                            }
                        }
                    }else if(2 == proto->protocol_type){
                        for(auto cmd = g_cm->get_dlt645_commands()->begin(); cmd != g_cm->get_dlt645_commands()->end(); cmd++){
                            //查找名称相同的指令，获取指令id
                            if(0 == cmd->second.name.compare(cmd_name->name)){
                                //联动设置指令                           
                                CMD_SET_CONST_VALUE data;
                                data.command = "CMD_SET_COMMAND_RULE";
                                data.commandId = 0;
                                data.commandType = "REQ";
                                data.devId = dev->second.id;
                                data.timestamp = get_timestamp();
                                data.params.cmdId = cmd->second.id;
                                data.params.value = cmd_name->val;
                                if(0 == strncmp(proto->protocol_name.c_str(), "CB001", strlen("CB001"))){
                                    int v = std::stoi(cmd_name->val);
                                    if(0 == v){
                                        data.params.value = "";
                                    }else if(1 == v){
                                        data.params.value = "0200";
                                    } else {
                                        data.params.value = "";
                                    }
                                } else if((0 == strncmp(proto->protocol_name.c_str(), "RCD", strlen("RCD"))) || 
                                    (0 == strncmp(proto->protocol_name.c_str(), "Breaker", strlen("Breaker"))) || 
                                    (0 == strncmp(proto->protocol_name.c_str(), "QCW92L6400A", strlen("QCW92L6400A"))) ||
                                    (0 == strncmp(proto->protocol_name.c_str(), "漏保断路器", strlen("漏保断路器")))){
                                    data.params.value = get_ptlk_value(data.devId, data.params.value, cmd_name->name);
                                    CLogger::getInstance()->log_i("获取到PTLK值：%s", data.params.value.c_str());
                                }
                                
                                std::string sendMsg = JsonManager::getInstance().get_set_const_value_msg(data);
                                CLogger::getInstance()->log_i("执行定值设置命令(dlt645)：%s", sendMsg.c_str());
                                std::string topic = RULE_COMMAND_TOPIC(std::string(g_sn));
                                g_mosquitto_manager->publish(topic.c_str(), sendMsg.length(), sendMsg.c_str());
                            }
                        }
                    }
                }
            }
        }
    }
    return 0;
}
//数据中心初始化
void init_datacenter()
{
    g_dcm = std::shared_ptr<DataCenterManager>(DataCenterManager::getInstance());
    g_dcm->init(g_cm, g_tm);
    g_dcm->set_handle_func(handle_set_value);
    g_dcm->connect(mosquitto_addr, mosquitto_port, NULL, NULL, 10);

#if 0
    //设备注册、模型设置已转移到配置改变触发，在此保留做为测试使用
    g_dcm->devregister_modelset_todc();
#endif
    CDBManager::getInstance()->remove_dev_guids();  //清除所有devguid
    //构建<dev,<point_name,104信息对象>>映射关系
    std::list<std::string> lstModelNames = g_dcm->dc_modelname_query_waitsubscribe();
    if (lstModelNames.size() > 0)
    {
        //查询模型
        std::list<ST_SINGLE_MODEL_INFO> lstModels;
        lstModels = g_dcm->dc_model_query(lstModelNames);

        //设备注册
        std::list<ST_REGISTER_MODEL_INFO> lstRegisterRelation;
        g_dcm->dc_register_relation_query(lstRegisterRelation);
        
        //模型、设备对比，不相同重新进行模型设置和设备注册
        bool model_corres = g_dcm->model_contrast(lstModels);
        bool dev_corres = g_dcm->regdev_contrast(lstRegisterRelation);
        CLogger::getInstance()->LOG_I("model contrast=%d, register dev contrast=%d",model_corres,dev_corres);
        if (!model_corres || !dev_corres)
        {
            CLogger::getInstance()->LOG_I("datacenter:model setup and device register redo");
            g_dcm->devregister_modelset_todc();

            lstModelNames.clear();
            lstModels.clear();
            lstRegisterRelation.clear();

            lstModelNames = g_dcm->dc_modelname_query_waitsubscribe();
            lstModels = g_dcm->dc_model_query(lstModelNames);
            g_dcm->dc_register_relation_query(lstRegisterRelation);
        }
        
        g_dcm->print_register_relation(lstRegisterRelation);
        if (lstModels.size() > 0 && (lstRegisterRelation.size() > 0))
        {
            CMappingRelationManager::getInstance()->build_dc_iec104_relevance(lstModels, lstRegisterRelation);
        }
    }else{
        CLogger::getInstance()->LOG_I("datacenter inited,query model name size is 0,start register.");
        g_dcm->devregister_modelset_todc();

        lstModelNames = g_dcm->dc_modelname_query_waitsubscribe();
        if (lstModelNames.size() > 0)
        {
            std::list<ST_SINGLE_MODEL_INFO> lstModels;
            lstModels = g_dcm->dc_model_query(lstModelNames);

            std::list<ST_REGISTER_MODEL_INFO> lstRegisterRelation;
            g_dcm->dc_register_relation_query(lstRegisterRelation);
            if (lstModels.size() > 0 && (lstRegisterRelation.size() > 0))
            {
                CMappingRelationManager::getInstance()->build_dc_iec104_relevance(lstModels, lstRegisterRelation);
            }
            g_dcm->print_register_relation(lstRegisterRelation);
        }
    }

}
//初始化映射关系管理---调用须在 数据中心初始化和report_manager之前
void init_maprelation_manager()
{
    CMappingRelationManager::getInstance()->init(g_cm);
    CMappingRelationManager::getInstance()->build_iec104_down_relevance();
    CMappingRelationManager::getInstance()->build_iec104_deadzonemp();
    CMappingRelationManager::getInstance()->build_points_relation();
}
//iec104模块初始化
void init_iec104_commHandle()
{
    auto iec104North = g_cm->get_iec104_rules();
    if (iec104North)
    {
        auto iec104Cfg = iec104North->begin();
        if (iec104Cfg != iec104North->end())
        {
            int enable= iec104Cfg->second.enable;
            if (enable <1)
            {
                CLogger::getInstance()->LOG_I("iec104 north enable is 0.");
                return;
            }
            g_104north_enable = true;

            int mode = iec104Cfg->second.mode;
            bool breverse = (mode == 2 ? true : false);
            CLogger::getInstance()->LOG_I("iec104 communation init finished,mode=%d",mode);
            g_iec104comm = std::make_shared<CIec104CommHandler>();
            g_iec104comm->init(g_cm, g_dcm, g_mosquitto_manager, g_tm,breverse);
            g_iec104comm->client_init();            
        }
    }
    else{
        CLogger::getInstance()->LOG_I("init iec104 no config info.");
    }
    

}
void init_report_manager(){
    
    CReportManager::getInstance().init(g_crm->c_mm,g_cm,g_dcm,g_iec104comm);
    auto edge_device = g_cm->get_edge_device();
    if(nullptr == edge_device){
        return ;
    }
    CReportManager::getInstance().run(edge_device->data_report_type, edge_device->report_period);
}
void init_nort_dlt698(){
    NetManager::getInstance().init(g_cm, "0.0.0.0", 8698, WORKING_MODE_SERVER);
}
//初始化本地配置
void init_settings(){
    Settings::getInstance().open(settings_filename);
    std::string value;
    if(0 == Settings::getInstance().read("mosquitto_addr", value)){
        snprintf(mosquitto_addr, sizeof(mosquitto_addr), "%s", value.c_str());
    }
    //
    if(0 == Settings::getInstance().read("mosquitto_port", value)){
        int port = atoi(value.c_str());
        if(0 < port){
            mosquitto_port = port;
        }
    }
    if(0 == Settings::getInstance().read("cloud_mosquitto_addr", value)){
        snprintf(cloud_mosquitto_addr, sizeof(cloud_mosquitto_addr), "%s", value.c_str());
    }
    //
    if(0 == Settings::getInstance().read("cloud_mosquitto_port", value)){
        int port = atoi(value.c_str());
        if(0 < port){
            cloud_mosquitto_port = port;
        }
    }
    //
    if(0 == Settings::getInstance().read("cloud_username", value)){
        snprintf(cloud_username, sizeof(cloud_username), "%s", value.c_str());
    }
    //
    if(0 == Settings::getInstance().read("cloud_password", value)){
        snprintf(cloud_password, sizeof(cloud_password), "%s", value.c_str());
    }

    //
    if (0 == Settings::getInstance().read("iec104_nodata_time", value)){
        int tlen = atoi(value.c_str());
        if (0 < tlen){
            g_no_recvdata_time = tlen;
        }
    }

    if(0 == Settings::getInstance().read("is_always_link_cloud", value)){
        g_is_always_link_cloud = atoi(value.c_str());
    }

    if (0 == Settings::getInstance().read("cz_patch_enable",value))
    {
        g_cangzhou_patch_enable = atoi(value.c_str());
    }
    //
    std::string tmp_str = get_version();
    Settings::getInstance().write("software_ver", tmp_str);
    tmp_str = get_code();
    Settings::getInstance().write("software_code", tmp_str);
    Settings::getInstance().save(settings_filename);
    Settings::getInstance().close();
}
void handle_task(){
    g_tm->run_task(g_cm, g_mosquitto_manager);
}
//
int main(int argc, char *argv[]){
    g_argv = argv;
    //解析命令行参数
    if(0 > parse_cmd(argc, argv)){
        return -1;
    }
    get_sn();
    //如果存在进程pemd，直接退出
    pid_t cur_pid = getpid();
    int samename_proc_id = get_processpid_byname("pemd",cur_pid);
    if ((0<samename_proc_id) && (samename_proc_id != cur_pid)){
        printf("pemd process exited.\n");
        return -1;
    }

    //初始化日志信息
    CLogger::getInstance()->init(log_filename, log_size, "PEMD", log_level);
    CLogger::getInstance()->LOG_I("-------------------------------pemd start----------------------------------");
    sleep(10);
    //初始化环境配置
    init_settings();
    mqtt_connect(mosquitto_addr, mosquitto_port);
    LicenseManager::GetInstance()->IsLicensed();
    //协议module、log、setting目录
    redirect_modulepath();
    //加载协议引擎模块
    IModule::getInstance().load_modules(module_dir); 
    
    //打开数据库
    init_db();
    std::shared_ptr<CONFIG_ALL> config = std::make_shared<CONFIG_ALL>();
    if(nullptr == get_all_config(config)){
        return -1;
    }
    //初始化本地mqtt
    init_mosquitto();
    //配置处理
    g_cm->parse(config);
    CLogger::getInstance()->LOG_I("pemd work config info inited.");

    init_uart_mode();
    //订阅串口收发主题
    subscribe_serial_topic(g_cm->get_interfaces());
    
    //初始化映射关系管理
    init_maprelation_manager();
    //初始化数据中心
    init_datacenter();

    //初始化云边通信
    init_cloud_edge_communication();
        
   //初始化iec104通信模块
    init_iec104_commHandle();
    //初始化信息上报管理模块
    init_report_manager();
    //任务处理
    handle_task();
    //初始化北向698
    init_nort_dlt698();
    //可优化，定时清理日志信息
    while(true){
        handle_storage_info();
        sleep(today_level_time_s());
    }

    g_iec104comm->client_stop();

    return 0;
}